package configmgr

import (
	"context"
	"fmt"

	"sync"

	"gitee.com/saroeleven/ginrcpv2/etcdmgr/etcdclient"
	"gitee.com/saroeleven/ginrcpv2/log"
)

const configPrefix = "conf/svc/"

type configManager struct {
	cache sync.Map
	once  sync.Once
}

type parseValue2Config func([]byte) (any, error)

func NewConfigManager() *configManager {
	return &configManager{}
}

// LoadAndWatchConfig 加载并监视配置文件变化，并自定义解析方式 (如 json, toml, yaml)。
func (configMgr *configManager) LoadAndWatchConfig(configKey string, parse parseValue2Config) (any, error) {
	mergeKey := configPrefix + configKey

	configMgr.once.Do(func() {
		_ = configMgr.loadAndWatch(mergeKey, parse)
	})

	conf, ok := configMgr.cache.Load(mergeKey)
	if !ok {
		return nil, fmt.Errorf("configuration for key %s not found", mergeKey)
	}

	return conf, nil
}

func (configMgr *configManager) loadAndWatch(mergeKey string, parse parseValue2Config) error {
	// create etcd client
	client, err := etcdclient.NewEtcdClient()
	if err != nil {
		return fmt.Errorf("failed to create etcd client: %w", err)
	}

	// watch config
	err = client.LoadAndWatchV3(
		context.TODO(),
		mergeKey,

		func(key, value []byte) {
			configMgr.configUpdate(mergeKey, value, parse)
		},

		func(key, value []byte) {
			configMgr.configDelete(mergeKey)
		})

	if err != nil {
		return fmt.Errorf("failed to watch config for key %s: %w", mergeKey, err)
	}
	return nil
}

// 当配置被更新时，解析配置并存储到缓存中
func (configMgr *configManager) configUpdate(mergeKey string, value []byte, parse parseValue2Config) {
	parsedValue, parseErr := parse(value)
	if parseErr != nil {
		log.Errorf("Failed to parse configuration for key %s: %v", mergeKey, parseErr)
		return
	}
	configMgr.cache.Store(mergeKey, parsedValue)
	log.Infof("Configuration for key %s updated", mergeKey)
}

// 当配置被删除时，从缓存中删除
func (configMgr *configManager) configDelete(mergeKey string) {
	configMgr.cache.Delete(mergeKey)
	log.Infof("Configuration for key %s deleted", mergeKey)
}
